/**
 * Copyright 2011 Renato de Jesus Manzoni
 * 
 * SED - Software Engineering and Dependability Research Group
 * 
 *     http://www.sed.ic.unicamp.br/
 * 
 * Distributed Systems Laboratory (LSD) in the Institute of Computing (IC) at University of Campinas (UNICAMP)
 * 
 *     http://www.lsd.ic.unicamp.br/
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package br.unicamp.ic.lsd.wscaa;

import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.cxf.endpoint.ClientCallback;
import org.perf4j.StopWatch;
import org.perf4j.commonslog.CommonsLogStopWatch;

import br.unicamp.ic.lsd.wscaa.concurrent.WSCAACallBackResults;
import br.unicamp.ic.lsd.wscaa.model.ServiceRequest;
import br.unicamp.ic.lsd.wscaa.model.ServiceResponse;

//TODO fazer graficos usandos gnu-plot e http://perf4j.codehaus.org/apidocs/org/perf4j/log4j/package-summary.html

/**
 * @author Renato de Jesus Manzoni <rjmanzoni@gmail.com>
 *
 */
public class WSCAAExecutor {
	private final List<WebService> wss;

	// private static final long TIME_WINDOW_RESOLUTION = 20L;

	// Map<String, BindingOperationInfo> bindOps;
	// Map<BindingOperationInfo, WebService> opWs;

	private Map<String, WebService> opWs;

	public WSCAAExecutor(List<WebService> wss) {
		this.wss = wss;
		buildWsOpMap();
	}

	private void buildWsOpMap() {

		opWs = new HashMap<String, WebService>();

		for (Iterator<WebService> iterator = wss.iterator(); iterator.hasNext();) {

			WebService ws = iterator.next();

			String[] ops = ws.getOperations();

			for (int i = 0; i < ops.length; i++) {
				opWs.put(ops[i], ws);
			}
		}

	}

	// talvez um LinkedHashMap com operations e objetos do parametro seja
	// melhor, porem a seguencia de opereations nao importa!!!
	public void executeWSCAA(Map<String, Object[]> workParallelFlow) {

		Map<String, ClientCallback> callBacksByOp = new HashMap<String, ClientCallback>();

		try {
			for (Iterator<String> iterator = workParallelFlow.keySet()
					.iterator(); iterator.hasNext();) {

				String key = iterator.next(); // get the key

				// BindingOperationInfo bo = bindOps.get(key); //get the
				// operation by key
				final StopWatch stopWatch = new CommonsLogStopWatch();

				WebService ws = opWs.get(key); // get the WebService that
												// contain the key
				stopWatch.stop("WSCAAExecutor.executeWSCAA.opWs.get");

				ClientCallback cb = new ClientCallback();

				ws.invokeAsyncMethod(cb, key, workParallelFlow.get(key)); // invoke
																			// the
																			// service

				callBacksByOp.put(key, cb);

			}

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public List<ServiceResponse> executeWSCAA(
			List<ServiceRequest> workParallelFlow) {

		final StopWatch stopWatch = new CommonsLogStopWatch();

		WSCAACallBackResults callBacks = new WSCAACallBackResults();

		WSCAManager.getInstance().start();

		try {
			for (Iterator<ServiceRequest> iterator = workParallelFlow
					.iterator(); iterator.hasNext();) {

				ServiceRequest request = iterator.next(); // get the key

				// get the WebService that contain the key
				WebService ws = opWs.get(request.getRequestName());

				ClientCallback cb = new ClientCallback();

				// invoke the service
				ws.invokeAsyncMethod(cb, request.getRequestName(),
						request.getParams());

				callBacks.addTask(request.getRequestName(), cb);

			}

		} catch (Exception e) {
			e.printStackTrace();
		}

		stopWatch.stop("WSCAAExecutor.executeWSCAA.execution");

		final StopWatch stopWatchReturn = new CommonsLogStopWatch();

		List<ServiceResponse> res = callBacks.getResults();

		// TODO depois que retornar o resultado, tavez seja interssante tratar
		// aqui os resultados quando exceptions acontecem

		stopWatchReturn.stop("WSCAAExecutor.executeWSCAA.result");

		return res;
	}

}
